home *** CD-ROM | disk | FTP | other *** search
/ BMUG Revelations / BMUG Revelations.toast / Utilities / Random / Commodore 64c / SOURCE / Floppy.c < prev    next >
Text File  |  1994-03-19  |  32KB  |  1,580 lines

  1. /*
  2.     Commodore 64 Emulator v0.2      Earle F. Philhower III 
  3.     Copyright (C) 1993-4            (st916w9r@dunx1.ocs.drexel.edu)
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. This file stolen from x64 0.2.1.  Most bugs in the file are of my own making.
  20. I've removed the 64 byte header so it'll run *.D64 images w/o conversion.
  21. Also, most of the ANSI calls have been xlated into native Mac FS calls or my
  22. own memory management routines.
  23.  
  24. The buffer allocations are no longer done w/malloc, but instead used buffers
  25. that are allocated only once.  This is necessary to avoid heap fragmentation
  26. on the non memory-mapping MacOS.
  27.  
  28.  * 1541.c -- 1541 Floppy Drive emulation. Emulator emulates 1541 reasonably
  29.  *         well as long as 1541 is used through ROM-interface (no
  30.  *         turboloaders supported). Also REL-file type is still missing.
  31.  *
  32.  * $Id: 1541.c,v 1.4 1993/11/10 01:55:34 jopi Exp $
  33.  *
  34.  * This file is part of Commodore 64 emulator.
  35.  * See README for copyright notice
  36.  *
  37.  *
  38.  * Written by
  39.  *   Teemu Rantanen (tvr@cs.hut.fi)
  40.  *
  41.  * .... yadda yadda yadda ....
  42.  *
  43.  */
  44.  
  45.  
  46. #include <stdio.h>
  47. #include <string.h>
  48.  
  49. #include "MemoryCalls.h"
  50. #include "Serial.h"
  51. #include "Floppy.h"
  52. #include "FileTypes.h"
  53.  
  54. typedef struct bufferinfo_s {
  55.     int     mode;    /* mode on this buffer */
  56.     int     readmode;    /* is this for reading or writing */
  57.     int     secondary;    /* this is not needed */
  58.     byte   *buffer;    /* use this to save data */
  59.     byte   *slot;    /* save data for directory-slot */
  60.     int     bufptr;    /* use this to save/read data to disk */
  61.     int     length;    /* directory-read length */
  62. }       bufferinfo_t;
  63.  
  64. typedef long off_t;
  65.  
  66. byte normBuffer[16][256];
  67. byte normSlot[16][32];
  68. byte dirBuffer[8192];
  69. static int floppyInDrive=0;
  70.  
  71.  
  72. #define BUFFER_NOT_IN_USE        0
  73. #define BUFFER_DIRECTORY_READ        1
  74. #define BUFFER_SEQUENTIAL        2
  75. #define BUFFER_MEMORY_BUFFER        3
  76. #define BUFFER_OTHER            4
  77. #define BUFFER_COMMAND_CHANNEL        5
  78.  
  79.  
  80. #define WRITE_BLOCK             512
  81.  
  82.  
  83. /*
  84.  * Actually, serial-code errors ...
  85.  */
  86.  
  87. #define SLOT_TYPE_OFFSET        2
  88. #define SLOT_FIRST_TRACK        3
  89. #define SLOT_FIRST_SECTOR        4
  90. #define SLOT_NAME_OFFSET        5
  91. #define SLOT_NR_BLOCKS            30
  92.  
  93. #define BAM_FIRST_TRACK            0
  94. #define BAM_FIRST_SECTOR        1
  95. #define BAM_FORMAT_TYPE            2
  96. #define BAM_BIT_MAP            4
  97. #define BAM_DISK_NAME            144
  98. #define BAM_DISK_ID            162
  99. #define BAM_VERSION            165
  100.  
  101.  
  102. #define BAM_SET(n)    (bamp[1+(n)/8] |= (1 << ((n) % 8)))
  103. #define BAM_CLR(n)    (bamp[1+(n)/8] &= ~(1 << ((n) % 8)))
  104. #define BAM_ISSET(n)  (bamp[1+(n)/8] & (1 << ((n) % 8)))
  105.  
  106.  
  107. static byte bam[256];
  108.  
  109. static int sector_map[36] =
  110. {
  111.     0,
  112.     21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
  113.     19, 19, 19, 19, 19, 19, 19,
  114.     18, 18, 18, 18, 18, 18,
  115.     17, 17, 17, 17, 17
  116. };
  117.  
  118.  
  119. static char *slot_type[] =
  120. {
  121.     "   ", "SEQ", "PRG", "USR", "REL", "   ", "   ", "   "
  122. };
  123.  
  124. static bufferinfo_t floppy_buffers[16];
  125.  
  126. static int floppy_find_slot;
  127. static byte floppy_find_buffer[256];
  128. static int floppy_find_current_track;
  129. static int floppy_find_current_sector;
  130.  
  131. short     FloppyActiveFd = -1;
  132.  
  133. static char *floppy_find_name;
  134. static int floppy_find_length;
  135. static int floppy_find_type;
  136.  
  137.  
  138. extern byte FloppyInitialize ( void );
  139. extern byte Open1541 ( char *name, int length, int secondary );
  140. extern byte Close1541 ( int secondary );
  141. extern byte Read1541 ( unsigned char *data, int secondary );
  142. extern byte Write1541 ( unsigned char data, int secondary );
  143. extern void Flush1541 ( int secondary );
  144. static int floppy_parse_name ( char *name, int length, char *realname, int *reallength, int *readmode, int *filetype );
  145. static int floppy_create_directory ( char *name, int length, int filetype, int secondary, unsigned char *outputptr );
  146. static void set_find_first_slot ( char *name, int length, int type );
  147. static unsigned char *find_next_slot ( void );
  148. static void no_a0_pads ( unsigned char *ptr, int l );
  149. static int floppy_read_block ( unsigned char *buf, int track, int sector );
  150. static int floppy_write_block ( unsigned char *buf, int track, int sector );
  151. static void floppy_error ( int code, int track, int sector );
  152. static void remove_slot ( unsigned char *slot );
  153. static int write_sequential_buffer ( unsigned char *slot, unsigned char *buf, int length );
  154. static int alloc_free_sector ( int *track, int *sector );
  155. static int allocate_sector ( int track, int sector );
  156. static off_t offset_from_track_and_sector ( int track, int sector );
  157. static int free_sector ( int track, int sector );
  158. static int floppy_name_match ( unsigned char *slot, char *name, int length, int type );
  159. static void floppy_close_all_channels ( void );
  160. static int do_initialize ( void );
  161. static int do_validate ( void );
  162. static int do_format ( char *name, unsigned char *id, unsigned char *minus );
  163. static int do_command_channel_write ( unsigned char *buf, int length );
  164. static int do_block_command ( char command, char *buffer );
  165. extern void attach_floppy_image ( char *name );
  166. static int mystrncpy ( unsigned char *d, unsigned char *s, int n );
  167. extern int write_fs ( unsigned char data, int secondary );
  168. extern int petconv ( int c );
  169. extern void petconvstring ( char *c );
  170. extern int read_fs ( unsigned char *data, int secondary );
  171. extern int open_fs ( char *name, int length, int secondary );
  172. extern int close_fs ( int secondary );
  173.  
  174. void InitializeFloppy(void)
  175. {
  176.     int i;
  177.     
  178.     for (i=0; i<15; i++) floppy_buffers[i].mode=BUFFER_NOT_IN_USE;
  179.  
  180.     floppy_buffers[15].mode=BUFFER_COMMAND_CHANNEL;
  181.     floppy_buffers[15].buffer=normBuffer[15];
  182.     
  183.     AddSerialDevice(8, Read1541, Write1541, Open1541, Close1541, Flush1541);
  184.  
  185.     floppy_error(73, 0, 0);
  186. }
  187.  
  188. byte Open1541(char *name, int length, int secondary)
  189. {
  190.     bufferinfo_t *p = &floppy_buffers[secondary];
  191.     char    realname[256];
  192.     int     reallength;
  193.     int     readmode;
  194.     int     filetype;
  195.  
  196.     byte *slot;
  197.     int     i;
  198.  
  199.     /*
  200.      * No floppy in drive ?
  201.      */
  202.     if (FloppyActiveFd < 0)
  203.     return kFloppyError;
  204.  
  205.     /*
  206.      * Clear error flag
  207.      */
  208.     floppy_error(0, 0, 0);
  209.  
  210.     /*
  211.      * If channel is command channel, name will be used as write. Return only
  212.      * status of last write ...
  213.      */
  214.     if (p -> mode == BUFFER_COMMAND_CHANNEL) {
  215.     int     i;
  216.     int     status = kSerialOK;
  217.     for (i = 0; i < length; i++)
  218.         status = Write1541(name[i], secondary);
  219.     return status;
  220.     }
  221.     /*
  222.      * In use ?
  223.      */
  224.     if (p -> mode != BUFFER_NOT_IN_USE) {
  225.     floppy_error(70, 0, 0);
  226.     return kFloppyError;
  227.     }
  228.     /*
  229.      * Filemode / type
  230.      */
  231.     if (secondary == 1)
  232.     readmode = 0;
  233.     else
  234.     readmode = 1;
  235.  
  236.     filetype = 0;
  237.  
  238.     i = floppy_parse_name(name, length, realname, &reallength,
  239.     &readmode, &filetype);
  240.  
  241.     if (i != kSerialOK)
  242.     return i;
  243.  
  244.     /*
  245.      * Internal buffer ?
  246.      */
  247.     if (*name == '#') {
  248.     p -> mode = BUFFER_MEMORY_BUFFER;
  249.     p -> buffer = normBuffer[secondary];
  250.     p -> bufptr = 0;
  251.     return kSerialOK;
  252.     }
  253.     /*
  254.      * Directory read
  255.      */
  256.     if (*name == '$') {
  257.     if (!readmode)
  258.         return kFloppyError;
  259.  
  260.     p -> mode = BUFFER_DIRECTORY_READ;
  261.     p -> buffer = dirBuffer;
  262.  
  263.     /*
  264.      * fix this someday
  265.      */
  266.     if (*realname != '$')
  267.         p -> length = floppy_create_directory(realname, reallength, filetype,
  268.         secondary, p -> buffer);
  269.     else
  270.         p -> length = floppy_create_directory("*", 1, 0, secondary,
  271.         p -> buffer);
  272.     p -> bufptr = 0;
  273.  
  274.     return kSerialOK;
  275.     }
  276.     /*
  277.      * now, set filetype according secondary address, if it was not specified
  278.      * on filename
  279.      */
  280.     if (!filetype)
  281.     filetype = secondary < 2 ? 2 : 1;
  282.  
  283.     /*
  284.      * Check that there is room on directory.
  285.      */
  286.     set_find_first_slot(name, length, 0);
  287.     slot = find_next_slot();
  288.  
  289.     p -> readmode = readmode;
  290.  
  291.     /*
  292.      * Open file for reading
  293.      */
  294.     if (readmode) {
  295.     int     type;
  296.     int     status;
  297.  
  298.     if (!slot) {
  299.         Close1541(secondary);
  300.         floppy_error(62, 0, 0);
  301.         return kFloppyError;
  302.     }
  303.     type = slot[SLOT_TYPE_OFFSET] & 0x07;
  304.  
  305.     if (type != filetype) {
  306.         floppy_error(64, 0, 0);
  307.         return kFloppyError;
  308.     }
  309.     /*
  310.      * Seq, Prg
  311.      */
  312.     if (type == 1 || type == 2) {
  313.         p -> mode = BUFFER_SEQUENTIAL;
  314.         p -> bufptr = 2;
  315.         p -> buffer = normBuffer[secondary];
  316.  
  317.         status = floppy_read_block(p -> buffer, (int) slot[SLOT_FIRST_TRACK],
  318.         (int) slot[SLOT_FIRST_SECTOR]);
  319.  
  320.         if (status < 0) {
  321.         Close1541(secondary);
  322.         return kFloppyError;
  323.         }
  324.         return kSerialOK;
  325.     }
  326.     /*
  327.      * Unsupported filetype
  328.      */
  329.     return kFloppyError;
  330.     }
  331.     /*
  332.      * Write
  333.      */
  334.     if (slot) {
  335.     if (*name == '@')
  336.         remove_slot(slot);
  337.     else {
  338.         Close1541(secondary);
  339.         floppy_error(63, 0, 0);
  340.         return kFloppyError;
  341.     }
  342.     }
  343.     /*
  344.      * Create slot information. (XXXX: should write directoryentry to disk ?)
  345.      */
  346.     p -> slot = normSlot[secondary];
  347.     memset(p -> slot, 0, 32);
  348.     memset(p -> slot + SLOT_NAME_OFFSET, 0xa0, 16);
  349.     memcpy(p -> slot + SLOT_NAME_OFFSET, realname, reallength);
  350.  
  351.     p -> slot[SLOT_TYPE_OFFSET] = filetype;
  352.  
  353.     p -> buffer = normBuffer[secondary];
  354.     p -> mode = BUFFER_SEQUENTIAL;
  355.     p -> bufptr = 2;
  356.  
  357.     return kSerialOK;
  358. }
  359.  
  360.  
  361. byte Close1541(int secondary)
  362. {
  363.     byte   *e;
  364.     bufferinfo_t *p = &floppy_buffers[secondary];
  365.  
  366.     switch (p -> mode) {
  367.       case BUFFER_NOT_IN_USE:
  368.     return kFloppyError;
  369.  
  370.       case BUFFER_MEMORY_BUFFER:
  371.       case BUFFER_DIRECTORY_READ:
  372.     p -> mode = BUFFER_NOT_IN_USE;
  373.     p -> buffer = NULL;
  374.     break;
  375.  
  376.       case BUFFER_SEQUENTIAL:
  377.     if (!p -> readmode) {
  378.         /*
  379.          * Flush bytes and write slot to directory
  380.          */
  381.         write_sequential_buffer(p -> slot, p -> buffer, p -> bufptr);
  382.         set_find_first_slot(NULL, -1, 0);
  383.  
  384.         e = find_next_slot();
  385.  
  386.         if (!e) {
  387.         p -> mode = BUFFER_NOT_IN_USE;
  388.         p -> buffer = NULL;
  389.  
  390.         floppy_error(72, 0, 0);
  391.         return kFloppyError;
  392.         }
  393.         p -> slot[SLOT_TYPE_OFFSET] |= 0x80;
  394.         memcpy(&floppy_find_buffer[floppy_find_slot * 32 + 2], p -> slot + 2,
  395.         30);
  396.  
  397.         floppy_write_block(floppy_find_buffer,
  398.         floppy_find_current_track,
  399.         floppy_find_current_sector);
  400.         floppy_write_block(bam, 18, 0);
  401.     }
  402.     p -> mode = BUFFER_NOT_IN_USE;
  403.     p -> buffer = NULL;
  404.     break;
  405.  
  406.       case BUFFER_COMMAND_CHANNEL:
  407.     floppy_close_all_channels();
  408.     break;
  409.  
  410.       default:
  411.       InternalError(0);
  412.     }
  413.  
  414.     return kSerialOK;
  415. }
  416.  
  417.  
  418. byte Read1541(unsigned char *data, int secondary)
  419. {
  420.     bufferinfo_t *p = &floppy_buffers[secondary];
  421.  
  422.     switch (p -> mode) {
  423.       case BUFFER_NOT_IN_USE:
  424.     floppy_error(61, 0, 0);
  425.     return kFloppyError;
  426.  
  427.       case BUFFER_DIRECTORY_READ:
  428.     if (p -> bufptr >= p -> length)
  429.         return kSerialEOF;
  430.     *data = p -> buffer[p -> bufptr];
  431.     p -> bufptr++;
  432.     break;
  433.  
  434.       case BUFFER_MEMORY_BUFFER:
  435.     if (p -> bufptr >= 256)
  436.         return kSerialEOF;
  437.     *data = p -> buffer[p -> bufptr];
  438.     p -> bufptr++;
  439.     break;
  440.  
  441.       case BUFFER_SEQUENTIAL:
  442.     if (!p -> readmode)
  443.         return kFloppyError;
  444.  
  445.     /*
  446.      * Read next block if needed
  447.      */
  448.     if (p -> buffer[0]) {
  449.         if (p -> bufptr >= 256) {
  450.         floppy_read_block(p -> buffer,
  451.             (int) p -> buffer[0],
  452.             (int) p -> buffer[1]);
  453.         p -> bufptr = 2;
  454.         }
  455.     } else {
  456.         if (p -> bufptr > p -> buffer[1])
  457.         return kSerialEOF;
  458.     }
  459.  
  460.     *data = p -> buffer[p -> bufptr];
  461.     p -> bufptr++;
  462.     break;
  463.  
  464.       case BUFFER_COMMAND_CHANNEL:
  465.     if (p -> bufptr > p -> length) {
  466.         floppy_error(0, 0, 0);
  467.         return kSerialEOF;
  468.     }
  469.     *data = p -> buffer[p -> bufptr];
  470.     p -> bufptr++;
  471.     break;
  472.  
  473.       default:
  474.         InternalError(0);
  475.     }
  476.  
  477.     return kSerialOK;
  478. }
  479.  
  480.  
  481. byte Write1541(unsigned char data, int secondary)
  482. {
  483.     int     total = 0;
  484.     int     e;
  485.     bufferinfo_t *p = &floppy_buffers[secondary];
  486.  
  487.     switch (p -> mode) {
  488.       case BUFFER_NOT_IN_USE:
  489.     floppy_error(61, 0, 0);
  490.     return kFloppyError;
  491.  
  492.       case BUFFER_DIRECTORY_READ:
  493.     floppy_error(60, 0, 0);
  494.     return kFloppyError;
  495.  
  496.       case BUFFER_MEMORY_BUFFER:
  497.     if (p -> bufptr >= 256)
  498.         return kFloppyError;
  499.     p -> buffer[p -> bufptr] = data;
  500.     p -> bufptr++;
  501.     return kSerialOK;
  502.  
  503.       case BUFFER_SEQUENTIAL:
  504.     if (p -> readmode)
  505.         return kFloppyError;
  506.  
  507.     if (p -> bufptr >= 256) {
  508.         p -> bufptr = 2;
  509.         e = write_sequential_buffer(p -> slot, p -> buffer, WRITE_BLOCK);
  510.         if (e < 0)
  511.         return kFloppyError;
  512.     }
  513.     p -> buffer[p -> bufptr] = data;
  514.     p -> bufptr++;
  515.     break;
  516.  
  517.       case BUFFER_COMMAND_CHANNEL:
  518.     if (p -> bufptr >= 256)
  519.         return kFloppyError;
  520.     p -> buffer[p -> bufptr] = data;
  521.     p -> bufptr++;
  522.     break;
  523.  
  524.       default:
  525.         InternalError(0);
  526.     }
  527.  
  528.     return total;
  529. }
  530.  
  531.  
  532. void Flush1541(int secondary)
  533. {
  534.     bufferinfo_t *p = &floppy_buffers[secondary];
  535.  
  536.     if (p -> mode != BUFFER_COMMAND_CHANNEL)
  537.     return;
  538.  
  539.     do_command_channel_write(p -> buffer, p -> bufptr);
  540.     p -> bufptr = 0;
  541.     floppy_error(0, 0, 0);
  542. }
  543.  
  544.  
  545.  
  546. /*
  547.  * Parse name realname, type and read/write mode. '@' on write must
  548.  * be checked elsewhere
  549.  */
  550. static int floppy_parse_name(char *name, int length, char *realname, int *reallength, int *readmode, int *filetype)
  551. {
  552.     char   *p;
  553.     char   *c;
  554.     int     t;
  555.  
  556.     p = (char *)memchr(name, ':', length);
  557.     if (p)
  558.     p++;
  559.     else
  560.     p = name;
  561.  
  562.     if (*name == '@' && p == name)
  563.     p++;
  564.  
  565.     t = length - (p - name);
  566.     *reallength = 0;
  567.     c = realname;
  568.  
  569.     while (t > 0 && *p != ',') {
  570.     t--;
  571.     (*reallength)++;
  572.     *c++ = *p++;
  573.     }
  574.  
  575.     /*
  576.      * Change modes ?
  577.      */
  578.     while (t > 0) {
  579.     t--;
  580.     p++;
  581.  
  582.     if (t == 0) {
  583.         return kFloppyError;
  584.     }
  585.     if (*p == 'R')
  586.         *readmode = 1;
  587.     else if (*p == 'W')
  588.         *readmode = 0;
  589.     else if (*p == 'S')
  590.         *filetype = 1;
  591.     else if (*p == 'P')
  592.         *filetype = 2;
  593.     else if (*p == 'U')
  594.         *filetype = 3;
  595.     else if (*p == 'R')
  596.         *filetype = 4;
  597.     else
  598.         return kFloppyError;
  599.  
  600.     c = (char *)memchr(p, ',', t);
  601.  
  602.     if (c) {
  603.         t -= (c - p);
  604.         p = c;
  605.     } else
  606.         t = 0;
  607.     }
  608.  
  609.     return kSerialOK;
  610. }
  611.  
  612.  
  613. #define SET_LO_HI(p, val) {*(p)++ = (val) & 0xff; *(p)++ = ((val)/256) & 0xff;}
  614.  
  615. /*
  616.  * Create directory listing.
  617.  * If filetype is 0, match for all
  618.  */
  619. static int floppy_create_directory(char *name, int length, int filetype, int secondary, unsigned char *outputptr)
  620. {
  621.     byte   *l;
  622.     byte *p;
  623.     byte   *tmpsl;
  624.     byte   *origptr = outputptr;
  625.     int     t;
  626.     int     bf;
  627.  
  628.     int     addr;
  629.  
  630.  
  631.     set_find_first_slot(name, length, filetype);
  632.  
  633.     l = outputptr;
  634.  
  635.     /*
  636.      * Start-address
  637.      */
  638.     addr = 0x401;
  639.     SET_LO_HI(l, addr);
  640.  
  641.     /*
  642.      * Set next line offset later
  643.      */
  644.     l += 2;
  645.  
  646.     /*
  647.      * Line number 0
  648.      */
  649.     SET_LO_HI(l, 0);
  650.  
  651.     /*
  652.      * Reverse on
  653.      */
  654.     *l++ = (char) 0x12;
  655.  
  656.     *l++ = '\"';
  657.     memcpy(l, &bam[BAM_DISK_NAME], 16);
  658.     no_a0_pads(l, 16);
  659.     l += 16;
  660.     *l++ = '\"';
  661.     *l++ = ' ';
  662.     memcpy(l, &bam[BAM_DISK_ID], 5);
  663.     no_a0_pads(l, 5);
  664.     l += 5;
  665.  
  666.     *l++ = 0;
  667.  
  668.     /*
  669.      * Address of next line
  670.      */
  671.     addr += ((l - outputptr) - 2);
  672.  
  673.     outputptr[2] = addr & 0xff;
  674.     outputptr[3] = (addr / 256) & 0xff;
  675.  
  676.     outputptr = l;
  677.  
  678.     /*
  679.      * Now, list files
  680.      */
  681.     while ((p = find_next_slot())) {
  682.     if (p[SLOT_TYPE_OFFSET]) {
  683.  
  684.         l += 2;
  685.  
  686.         /*
  687.          * Length and spaces
  688.          */
  689.         t = p[SLOT_NR_BLOCKS] + p[SLOT_NR_BLOCKS + 1] * 256;
  690.  
  691.         SET_LO_HI(l, t);
  692.  
  693.         if (t < 10)
  694.         *l++ = ' ';
  695.         if (t < 100)
  696.         *l++ = ' ';
  697.  
  698.         /*
  699.          * name
  700.          */
  701.         *l++ = ' ';
  702.         *l++ = '\"';
  703.         memcpy(l, &p[SLOT_NAME_OFFSET], 16);
  704.  
  705.         for (t = 0; (t < 16) && (p[SLOT_NAME_OFFSET + t] != 0xa0);)
  706.         t++;
  707.  
  708.         no_a0_pads(l, 16);
  709.  
  710.         l[16] = ' ';
  711.         l[t] = '\"';
  712.         l += 17;
  713.  
  714.         /*
  715.          * type
  716.          */
  717.         *l++ = p[SLOT_TYPE_OFFSET] & 0x80 ? ' ' : '*';
  718.  
  719.         tmpsl = (byte *)slot_type[p[SLOT_TYPE_OFFSET] & 0x07];
  720.  
  721.         memcpy(l, tmpsl, 3);
  722.         l += 3;
  723.  
  724.         /*
  725.          * End
  726.          */
  727.         *l++ = ' ';
  728.         *l++ = ' ';
  729.         *l++ = (char) 0;
  730.  
  731.         /*
  732.          * New address
  733.          */
  734.         addr += l - outputptr;
  735.  
  736.         outputptr[0] = addr & 0xff;
  737.         outputptr[1] = (addr / 256) & 0xff;
  738.  
  739.         outputptr = l;
  740.     }
  741.     }
  742.  
  743.     /*
  744.      * calculate blocks free
  745.      */
  746.     bf = 0;
  747.  
  748.     for (t = 1; t <= 35; t++) {
  749.     if (t != 18)
  750.         bf += bam[BAM_BIT_MAP + 4 * (t - 1)];
  751.     }
  752.  
  753.     *l++ = 0;
  754.     *l++ = 0;
  755.     SET_LO_HI(l, bf);
  756.     memcpy(l, "BLOCKS FREE.", 12);
  757.     l += 12;
  758.     *l++ = (char) 0;
  759.  
  760.     addr += l - outputptr;
  761.  
  762.     outputptr[0] = addr & 0xff;
  763.     outputptr[1] = (addr / 256) & 0xff;
  764.  
  765.     /*
  766.      * end
  767.      */
  768.     *l++ = (char) 0;
  769.     *l++ = (char) 0;
  770.     *l++ = (char) 0;
  771.  
  772.     return l - origptr;
  773. }
  774.  
  775.  
  776.  
  777. /*
  778.  * Initialize slot find
  779.  */
  780. static void set_find_first_slot(char *name, int length, int type)
  781. {
  782.     floppy_find_name = name;
  783.     floppy_find_length = length;
  784.     floppy_find_type = type;
  785.  
  786.     /*
  787.      * Make sure find_next_slot() loads first directoryblock ...
  788.      */
  789.     floppy_find_slot = 8;
  790.     floppy_read_block(floppy_find_buffer, 18, 0);
  791. }
  792.  
  793. static byte *find_next_slot(void)
  794. {
  795.     static byte return_slot[32];
  796.     int     status;
  797.  
  798.     floppy_find_slot++;
  799.  
  800.     /*
  801.      * Loop all directoryblocks staring from track 18, sector 1
  802.      */
  803.     do {
  804.     /*
  805.      * Load next(first) directory block ?
  806.      */
  807.     if (floppy_find_slot >= 8) {
  808.         if (!(*floppy_find_buffer))
  809.         return NULL;
  810.  
  811.         floppy_find_slot = 0;
  812.  
  813.         floppy_find_current_track = (int) floppy_find_buffer[0];
  814.         floppy_find_current_sector = (int) floppy_find_buffer[1];
  815.  
  816.         status = floppy_read_block(floppy_find_buffer,
  817.         floppy_find_current_track,
  818.         floppy_find_current_sector);
  819.     }
  820.     while (floppy_find_slot < 8) {
  821.         if (floppy_name_match(&floppy_find_buffer[floppy_find_slot * 32],
  822.             floppy_find_name, floppy_find_length,
  823.             floppy_find_type)) {
  824.         memcpy(return_slot,
  825.             &floppy_find_buffer[floppy_find_slot * 32], 32);
  826.         return return_slot;
  827.         }
  828.         floppy_find_slot++;
  829.     }
  830.     } while (*floppy_find_buffer);
  831.  
  832.     /*
  833.      * If length < 0, create new directory-entry if possible
  834.      */
  835.     if (floppy_find_length < 0) {
  836.     int     s;
  837.  
  838.     for (s = 1; s < sector_map[18]; s++) {
  839.         if (allocate_sector(18, s)) {
  840.         floppy_find_buffer[0] = 18;
  841.         floppy_find_buffer[1] = s;
  842.         floppy_write_block(floppy_find_buffer,
  843.             floppy_find_current_track,
  844.             floppy_find_current_sector);
  845.         floppy_find_slot = 0;
  846.         memset(floppy_find_buffer, 0, 256);
  847.         floppy_find_buffer[1] = 0xff;
  848.         floppy_find_current_sector = s;
  849.         return floppy_find_buffer;
  850.         }
  851.     }
  852.  
  853.     }
  854.     return NULL;
  855. }
  856.  
  857.  
  858. static void no_a0_pads(unsigned char *ptr, int l)
  859. {
  860.     while (l--) {
  861.     if (*ptr == 0xa0)
  862.         *ptr = 0x20;
  863.  
  864.     ptr++;
  865.     }
  866. }
  867.  
  868.  
  869.  
  870. /*
  871.  * Read one block
  872.  */
  873. static int floppy_read_block(unsigned char *buf, int track, int sector)
  874. {
  875.     long offset, len;
  876.  
  877.     offset=offset_from_track_and_sector(track, sector);
  878.     if (offset<0) return -1;
  879.  
  880.     SetFPos(FloppyActiveFd, fsFromStart, offset);
  881.     len=256;
  882.     FSRead(FloppyActiveFd, &len, buf);
  883.     if (len<256) DebugStr("\pFloppy read error");
  884.     return 0;
  885. }
  886.  
  887.  
  888.  
  889. /*
  890.  * Write one block
  891.  */
  892. static int floppy_write_block(unsigned char *buf, int track, int sector)
  893. {
  894.     long offset, len;
  895.  
  896.     offset=offset_from_track_and_sector(track, sector);
  897.     if (offset<0) return -1;
  898.  
  899.     SetFPos(FloppyActiveFd, fsFromStart, offset);
  900.     len=256;
  901.     FSWrite(FloppyActiveFd, &len, buf);
  902.     if (len<256) DebugStr("\pFloppy write error");
  903.     return 0;
  904. }
  905.  
  906.  
  907. /*
  908.  * Error messages
  909.  */
  910. typedef struct errortext_s {
  911.     int     nr;
  912.     char   *text;
  913. }       errortext_t;
  914.  
  915. static errortext_t floppy_error_messages[] =
  916. {
  917.     {0, "OK"},
  918.     {1, "FILES SCRATCHED"},
  919.     {30, "SYNTAX ERROR"},
  920.     {60, "WRITE FILE OPEN"},
  921.     {61, "FILE NOT OPEN"},
  922.     {62, "FILE NOT FOUND"},
  923.     {63, "FILE EXISTS"},
  924.     {64, "FILE TYPE MISMATCH"},
  925.     {70, "NO CHANNEL"},
  926.     {72, "DISK FULL"},
  927.     {73, "TVR 1541 EMULATOR V1.0"},
  928.     {-1, 0},
  929. };
  930.  
  931.  
  932. /*
  933.  * Should set values to somewhere so that they could be read from
  934.  * command channel
  935.  */
  936. static void floppy_error(int code, int track, int sector)
  937. {
  938.     char   *message;
  939.     bufferinfo_t *p = &floppy_buffers[15];
  940.  
  941.     errortext_t *e = &floppy_error_messages[0];
  942.  
  943.     while (e -> nr >= 0 && e -> nr != code)
  944.     e++;
  945.  
  946.     if (e -> nr >= 0)
  947.     message = e -> text;
  948.     else
  949.     message = "UNKNOWN ERROR NUMBER";
  950.  
  951.     sprintf((char *)p -> buffer, "%02d, %s,%d,%d", code, message, track, sector);
  952.     p -> length = strlen((char *)p -> buffer);
  953.     p -> bufptr = 0;
  954. }
  955.  
  956.  
  957. static void remove_slot(unsigned char *slot)
  958. {
  959.     byte    buf[256];
  960.     int     tmp;
  961.     int     t, s;
  962.  
  963.     /*
  964.      * Find slot
  965.      */
  966.     for (tmp = 0; (tmp < 16) && slot[SLOT_NAME_OFFSET + tmp] != 0xa0; tmp++);
  967.  
  968.     set_find_first_slot((char *)&slot[SLOT_NAME_OFFSET], tmp,
  969.     slot[SLOT_TYPE_OFFSET] & 0x07);
  970.  
  971.     /*
  972.      * If slot slot found, remove
  973.      */
  974.     if (find_next_slot()) {
  975.     /*
  976.      * Free all buffers from bam
  977.      */
  978.     t = (int) floppy_find_buffer[floppy_find_slot * 32 + SLOT_FIRST_TRACK];
  979.     s = (int) floppy_find_buffer[floppy_find_slot * 32 + SLOT_FIRST_SECTOR];
  980.  
  981.     while (t) {
  982.         free_sector(t, s);
  983.         floppy_read_block(buf, t, s);
  984.         t = (int) buf[0];
  985.         s = (int) buf[1];
  986.     }
  987.  
  988.     /*
  989.      * Update bam
  990.      */
  991.     floppy_write_block(bam, 18, 0);
  992.  
  993.     /*
  994.      * Update directory entry
  995.      */
  996.     floppy_find_buffer[floppy_find_slot * 32 + SLOT_TYPE_OFFSET] = 0;
  997.     floppy_write_block(floppy_find_buffer,
  998.         floppy_find_current_track,
  999.         floppy_find_current_sector);
  1000.     }
  1001. }
  1002.  
  1003.  
  1004.  
  1005. static int write_sequential_buffer(unsigned char *slot, unsigned char *buf, int length)
  1006. {
  1007.     static int t = 0, s;
  1008.     int     t_new, s_new;
  1009.     int     e;
  1010.  
  1011.     /*
  1012.      * First block of a file ?
  1013.      */
  1014.     if (t == 0) {
  1015.     e = alloc_free_sector(&t, &s);
  1016.     if (e < 0) {
  1017.         floppy_error(72, 0, 0);
  1018.         return -1;
  1019.     }
  1020.     slot[SLOT_FIRST_TRACK] = t;
  1021.     slot[SLOT_FIRST_SECTOR] = s;
  1022.     }
  1023.     if (length == WRITE_BLOCK) {
  1024.     /*
  1025.      * Write current sector and allocate next
  1026.      */
  1027.     e = alloc_free_sector(&t_new, &s_new);
  1028.     if (e < 0) {
  1029.         floppy_error(72, 0, 0);
  1030.         return -1;
  1031.     }
  1032.     buf[0] = t_new;
  1033.     buf[1] = s_new;
  1034.  
  1035.     floppy_write_block(buf, t, s);
  1036.  
  1037.     t = t_new;
  1038.     s = s_new;
  1039.  
  1040.     if (!(++slot[SLOT_NR_BLOCKS]))
  1041.         ++slot[SLOT_NR_BLOCKS + 1];
  1042.  
  1043.     } else {
  1044.     /*
  1045.      * Write last block
  1046.      */
  1047.     buf[0] = 0;
  1048.     buf[1] = length - 1;
  1049.  
  1050.     floppy_write_block(buf, t, s);
  1051.  
  1052.     t = 0;
  1053.  
  1054.     if (!(++slot[SLOT_NR_BLOCKS]))
  1055.         ++slot[SLOT_NR_BLOCKS + 1];
  1056.     }
  1057.     return 0;
  1058. }
  1059.  
  1060.  
  1061.  
  1062. static int alloc_free_sector(int *track, int *sector)
  1063. {
  1064.     int     t, s;
  1065.  
  1066.     for (t = 17; t >= 1; t--) {
  1067.     for (s = 0; s < sector_map[t]; s++) {
  1068.         if (allocate_sector(t, s)) {
  1069.         *track = t;
  1070.         *sector = s;
  1071.         return 0;
  1072.         }
  1073.     }
  1074.     }
  1075.  
  1076.     for (t = 19; t <= 35; t++) {
  1077.     for (s = 0; s < sector_map[t]; s++) {
  1078.         if (allocate_sector(t, s)) {
  1079.         *track = t;
  1080.         *sector = s;
  1081.         return 0;
  1082.         }
  1083.     }
  1084.     }
  1085.     return -1;
  1086. }
  1087.  
  1088.  
  1089. static int allocate_sector(int track, int sector)
  1090. {
  1091.     /*
  1092.      * Macros use this
  1093.      */
  1094.     byte   *bamp;
  1095.  
  1096.     bamp = &bam[BAM_BIT_MAP + 4 * (track - 1)];
  1097.  
  1098.     if (BAM_ISSET(sector)) {
  1099.     (*bamp)--;
  1100.     BAM_CLR(sector);
  1101.  
  1102.     return 1;
  1103.     }
  1104.     return 0;
  1105. }
  1106.  
  1107.  
  1108. /*
  1109.  * Return block offset on 'disk file' according to track and sector
  1110.  */
  1111. static off_t offset_from_track_and_sector(int track, int sector)
  1112. {
  1113.     int     sectors, i;
  1114.  
  1115.     if ((track < 1) || (track > 35))
  1116.     return (-1);
  1117.  
  1118.     for (sectors = 0, i = 1; i < track; i++) {
  1119.     sectors += sector_map[i];
  1120.     }
  1121.  
  1122.     if ((sector < 0) || (sector >= sector_map[track]))
  1123.     return (-1);
  1124.  
  1125.     sectors += sector;
  1126.  
  1127.     return 256L * sectors;
  1128. }
  1129.  
  1130.  
  1131.  
  1132. static int free_sector(int track, int sector)
  1133. {
  1134.     byte   *bamp;
  1135.  
  1136.     bamp = &bam[BAM_BIT_MAP + 4 * (track - 1)];
  1137.  
  1138.     if (!(BAM_ISSET(sector))) {
  1139.     BAM_SET(sector);
  1140.     (*bamp)++;
  1141.     return 1;
  1142.     }
  1143.     return 0;
  1144. }
  1145.  
  1146.  
  1147. /*
  1148.  * If type is 0, match for next slot with same name
  1149.  * If type is nonzero, match next that has the same id and name
  1150.  */
  1151. static int floppy_name_match(unsigned char *slot, char *name, int length, int type)
  1152. {
  1153.     int     i;
  1154.     /* int comma = 0; */
  1155.  
  1156.     if (length < 0) {
  1157.     if (slot[SLOT_TYPE_OFFSET])
  1158.         return 0;
  1159.     else
  1160.         return 1;
  1161.     }
  1162.     if (!slot[SLOT_TYPE_OFFSET])
  1163.     return 0;
  1164.  
  1165.     if (length >= 16)
  1166.     length = 16;
  1167.  
  1168.     for (i = 0; i < length; i++) {
  1169.     switch (name[i]) {
  1170.       case '?':
  1171.         /*
  1172.          * Match any character
  1173.          */
  1174.         break;
  1175.  
  1176.       case '*':
  1177.         /*
  1178.          * Make a match
  1179.          */
  1180.         i = 16;
  1181.         break;
  1182.  
  1183.       default:
  1184.         if ((byte)name[i] != slot[i + SLOT_NAME_OFFSET])
  1185.         return 0;
  1186.     }
  1187.     }
  1188.  
  1189.     /*
  1190.      * Got name match ?
  1191.      */
  1192.     if (i < 16 && slot[SLOT_NAME_OFFSET + i] != 0xa0)
  1193.     return 0;
  1194.  
  1195.     if (type && type != (slot[SLOT_TYPE_OFFSET] & 0x07))
  1196.     return 0;
  1197.  
  1198.     return 1;
  1199. }
  1200.  
  1201.  
  1202.  
  1203. /*
  1204.  * Close all channels. This happens on 'I' -command and on command-
  1205.  * channel close
  1206.  */
  1207. void floppy_close_all_channels(void)
  1208. {
  1209.     int     i;
  1210.     bufferinfo_t *p;
  1211.  
  1212.     for (i = 0; i <= 15; i++) {
  1213.     p = &floppy_buffers[i];
  1214.  
  1215.     if (p -> mode != BUFFER_NOT_IN_USE && p -> mode != BUFFER_COMMAND_CHANNEL)
  1216.         Close1541(i);
  1217.     }
  1218. }
  1219.  
  1220.  
  1221. static int do_initialize(void)
  1222. {
  1223.  
  1224.     floppy_close_all_channels();
  1225.     return kSerialOK;
  1226. }
  1227.  
  1228. static int do_validate(void)
  1229. {
  1230.     int     t, s;
  1231.     byte *b;
  1232.     byte    tmp[256];
  1233.  
  1234.     do_initialize();
  1235.  
  1236.     b = (byte *) bam + BAM_BIT_MAP;
  1237.  
  1238.     for (t = 1; t <= 35; t++) {
  1239.     *b++ = 0;
  1240.     *b++ = 0;
  1241.     *b++ = 0;
  1242.     *b++ = 0;
  1243.  
  1244.     for (s = 0; s < sector_map[t]; s++)
  1245.         free_sector(t, s);
  1246.     }
  1247.  
  1248.     set_find_first_slot("*", 1, 0);
  1249. /*
  1250.     First map out the directory itself.    -Dan Miner
  1251.     And another one bites the dust....  :)
  1252. */
  1253.     t = 18; s = 0;
  1254.     while(t) {
  1255.         allocate_sector(t, s);
  1256.         floppy_read_block(tmp, t, s);
  1257.         t = (int) tmp[0];
  1258.         s = (int) tmp[1];
  1259.     }
  1260.  
  1261.     while ((b = (byte *) find_next_slot())) {
  1262.     if (b[SLOT_TYPE_OFFSET]) {
  1263.         floppy_find_buffer[floppy_find_slot * 32 + SLOT_TYPE_OFFSET] |= 0x80;
  1264.         floppy_write_block(floppy_find_buffer, floppy_find_current_track,
  1265.         floppy_find_current_sector);
  1266.         t = (int) b[SLOT_FIRST_TRACK];
  1267.         s = (int) b[SLOT_FIRST_SECTOR];
  1268.  
  1269.         while (t) {
  1270.         allocate_sector(t, s);
  1271.         floppy_read_block(tmp, t, s);
  1272.         t = (int) tmp[0];
  1273.         s = (int) tmp[1];
  1274.         }
  1275.     }
  1276.     }
  1277.  
  1278.     floppy_write_block(bam, 18, 0);
  1279.     return kSerialOK;
  1280. }
  1281.  
  1282.  
  1283. static int do_format(char *name, unsigned char *id, unsigned char *minus)
  1284. {
  1285.     byte    tmp[256];
  1286.     int     status;
  1287.  
  1288.     byte    null = 0;
  1289.  
  1290.     if (!name) {
  1291.     floppy_error(30, 0, 0);
  1292.     return kFloppyError;
  1293.     }
  1294.     /*
  1295.      * If id, skip comma
  1296.      */
  1297.     if (id)
  1298.     *id++ = 0;
  1299.     else
  1300.     id = &null;
  1301.  
  1302.     /*
  1303.      * Make dir-entry
  1304.      */
  1305.     memset(tmp, 0, 256);
  1306.     tmp[1] = 255;
  1307.     floppy_write_block(tmp, 18, 1);
  1308.  
  1309.     /*
  1310.      * Make bam
  1311.      */
  1312.     memset(bam, 0, 256);
  1313.     bam[0] = 18;
  1314.     bam[1] = 1;
  1315.     bam[2] = 65;
  1316.     memset(bam + BAM_DISK_NAME, 0xa0, 16);
  1317.     mystrncpy(bam + BAM_DISK_NAME, (byte *)name + 1, 16);
  1318.  
  1319.     memset(bam + BAM_DISK_ID, 0xa0, 5);
  1320.     mystrncpy(bam + BAM_DISK_ID, id, 2);
  1321.     bam[BAM_VERSION] = 50;
  1322.     bam[BAM_VERSION + 1] = 65;
  1323.     status = do_validate();
  1324.     allocate_sector(18, 1);        /* first directory block-  Dan Miner */
  1325.     floppy_write_block(bam, 18, 0);
  1326.     return status;
  1327. }
  1328.  
  1329.  
  1330. static int do_command_channel_write(unsigned char *buf, int length)
  1331. {
  1332.     int     status = kFloppyError;
  1333.     static byte p[256];
  1334.     char   *name;
  1335.     byte   *minus;
  1336.     byte   *id;
  1337.  
  1338.     memcpy(p, buf, length);
  1339.     p[length] = 0;
  1340.  
  1341.     name = (char *)memchr(p, ':', length);
  1342.     id = (byte *)memchr(p, ',', length);
  1343.     minus = (byte *)memchr(p, '-', length);
  1344.  
  1345.     floppy_error(0, 0, 0);
  1346.  
  1347.     switch (p[0]) {
  1348.       case 'N':
  1349.     status = do_format(name, id, minus);
  1350.     break;
  1351.       case 'C':
  1352.     break;
  1353.  
  1354.       case 'R':
  1355.     break;
  1356.  
  1357.       case 'S':
  1358.     break;
  1359.  
  1360.       case 'I':
  1361.     status = do_initialize();
  1362.     break;
  1363.  
  1364.       case 'V':
  1365.     status = do_validate();
  1366.     break;
  1367.  
  1368.       case 'B':
  1369.     if (!minus || !name)
  1370.         floppy_error(30, 0, 0);
  1371.     else
  1372.         status = do_block_command(minus[1], name + 1);
  1373.     break;
  1374.  
  1375.       case 'U':
  1376.     switch (p[1]) {
  1377.       case '1':
  1378.       case 'A':
  1379.         if (name)
  1380.         status = do_block_command('R', name + 1);
  1381.         break;
  1382.  
  1383.       case '2':
  1384.       case 'B':
  1385.         if (name)
  1386.         status = do_block_command('W', name + 1);
  1387.         break;
  1388.     }
  1389.     break;
  1390.  
  1391.     }
  1392.  
  1393.     return status;
  1394. }
  1395.  
  1396.  
  1397.  
  1398. static int do_block_command(char command, char *buffer)
  1399. {
  1400.     int     l;
  1401.  
  1402.     int     channel = 0;
  1403.     int     drive = 0;
  1404.     int     track = 0;
  1405.     int     sector = 0;
  1406.     int     position = 0;
  1407.  
  1408.     switch (command) {
  1409.       case 'R':
  1410.       case 'W':
  1411.     l = sscanf(buffer, "%d %d %d %d", &channel, &drive,
  1412.         &track, §or);
  1413.     if (l < 4) {
  1414.         l = sscanf(buffer, "%d,%d,%d,%d", &channel, &drive,
  1415.         &track, §or);
  1416.         if (l < 4) {
  1417.         floppy_error(30, 0, 0);
  1418.         return kFloppyError;
  1419.         }
  1420.     }
  1421.     if (floppy_buffers[channel].mode != BUFFER_MEMORY_BUFFER) {
  1422.         floppy_error(30, 0, 0);
  1423.         return kFloppyError;
  1424.     }
  1425.     if (command == 'W')
  1426.         floppy_write_block(floppy_buffers[channel].buffer,
  1427.         track, sector);
  1428.     else
  1429.         floppy_read_block(floppy_buffers[channel].buffer,
  1430.         track, sector);
  1431.  
  1432.     floppy_buffers[channel].bufptr = 0;
  1433.     break;
  1434.  
  1435.       case 'A':
  1436.       case 'F':
  1437.     l = sscanf(buffer, "%d %d %d", &drive, &track, §or);
  1438.  
  1439.     if (l < 3) {
  1440.         l = sscanf(buffer, "%d,%d,%d", &drive, &track, §or);
  1441.  
  1442.         if (l < 3) {
  1443.         floppy_error(30, 0, 0);
  1444.         return kFloppyError;
  1445.         }
  1446.     }
  1447.     if (command == 'A')
  1448.         allocate_sector(track, sector);
  1449.     else
  1450.         free_sector(track, sector);
  1451.     break;
  1452.  
  1453.       case 'P':
  1454.     l = sscanf(buffer, "%d %d", &channel, &position);
  1455.  
  1456.     if (l < 2) {
  1457.         l = sscanf(buffer, "%d,%d", &channel, &position);
  1458.  
  1459.         if (l < 2) {
  1460.         floppy_error(30, 0, 0);
  1461.         return kFloppyError;
  1462.         }
  1463.     }
  1464.     floppy_buffers[channel].bufptr = position;
  1465.     break;
  1466.  
  1467.       default:
  1468.     floppy_error(30, 0, 0);
  1469.     return kFloppyError;
  1470.     }
  1471.     return kSerialOK;
  1472. }
  1473.  
  1474.  
  1475.  
  1476. void AttachFloppyImage(FSSpec *spec)
  1477. {
  1478.     floppy_close_all_channels();
  1479.  
  1480.     if (floppyInDrive) FSClose(FloppyActiveFd);
  1481.     floppyInDrive=0;
  1482.  
  1483.     if (spec==NULL)
  1484.     {
  1485.         floppyInDrive=0;
  1486.         return;
  1487.     }
  1488.  
  1489.     if (FSpOpenDF(spec, fsRdWrPerm, &FloppyActiveFd)!=noErr)
  1490.     {
  1491.         floppyInDrive=0;
  1492.         return;
  1493.     }
  1494.  
  1495.     floppyInDrive=1;
  1496.     floppy_read_block(bam, 18, 0);
  1497. }
  1498.  
  1499. static int mystrncpy(unsigned char *d, unsigned char *s, int n)
  1500. {
  1501.     while (n-- && *s)
  1502.     *d++=*s++;
  1503.     return (n);
  1504. }
  1505.  
  1506. void CreateImage(FSSpec *spec)
  1507. {
  1508.     byte block[256];
  1509.     int    i;
  1510.     long len;
  1511.     short fnum;
  1512.     
  1513.     for (i=0; i<256; i++) block[i]=0;
  1514.  
  1515.     FSpCreate(spec, (OSType)APPLTYPE, (OSType)DISKFTYPE, 0);
  1516.     FSpOpenDF(spec, fsRdWrPerm, &fnum);
  1517.     
  1518.     len=256;
  1519.     for (i=0; i < 683; i++) FSWrite(fnum, &len, block);
  1520.     FSClose(fnum);
  1521. }
  1522.  
  1523.  
  1524. void FloppyCreateImage(void)
  1525. {
  1526.     StandardFileReply reply;
  1527.     static char *initString="N0:MAC64 FLOPPY,00";
  1528.     
  1529.     StandardPutFile("\pCreate New Image:", "\pDISK.D64", &reply);
  1530.     
  1531.     if (reply.sfGood)
  1532.     {
  1533.         CreateImage(&reply.sfFile);
  1534.         AttachFloppyImage(&reply.sfFile);
  1535.         do_command_channel_write((byte *)initString, strlen(initString));
  1536.     }
  1537. }
  1538.  
  1539. void FloppySelectImage(void)
  1540. {
  1541.     StandardFileReply reply;
  1542.     
  1543.     StandardGetFile(nil, (short)-1, nil, &reply);
  1544.     if (reply.sfGood)
  1545.     {
  1546.         AttachFloppyImage(&reply.sfFile);
  1547.         do_initialize();
  1548.     }
  1549. }
  1550. void FloppyDirectory(void) {}
  1551. void FloppyCopyTo(void)
  1552. {
  1553.     StandardFileReply reply;
  1554.     short fNum;
  1555.     unsigned long size;
  1556.     byte data;
  1557.     
  1558.     if (floppyInDrive==0) return;
  1559.         
  1560.     StandardGetFile(nil, (short)-1, nil, &reply);
  1561.     if (reply.sfGood)
  1562.     {
  1563.         FSpOpenDF(&reply.sfFile, fsRdPerm, &fNum);
  1564.         PetConvString(reply.sfFile.name);
  1565.         Open1541((char *)(&reply.sfFile.name[1]), (int)reply.sfFile.name[0], 1);
  1566.         size=1;
  1567.         while (size)
  1568.         {
  1569.             FSRead(fNum, (long *)&size, &data);
  1570.             if (size) Write1541(data, 1);
  1571.         }
  1572.         FSClose(fNum);
  1573.         Close1541(1);
  1574.     }
  1575. }
  1576.  
  1577. void FloppyCopyFrom(void)
  1578. {
  1579. }
  1580.